import { EndpointParameters } from "@smithy/types";

/**
 * @internal
 */
export const resolveParamsForS3 = async (endpointParams: EndpointParameters) => {
  const bucket = (endpointParams?.Bucket as string) || "";

  if (typeof endpointParams.Bucket === "string") {
    endpointParams.Bucket = bucket.replace(/#/g, encodeURIComponent("#")).replace(/\?/g, encodeURIComponent("?"));
  }

  if (isArnBucketName(bucket)) {
    if (endpointParams.ForcePathStyle === true) {
      throw new Error("Path-style addressing cannot be used with ARN buckets");
    }
  } else if (
    !isDnsCompatibleBucketName(bucket) ||
    (bucket.indexOf(".") !== -1 && !String(endpointParams.Endpoint).startsWith("http:")) ||
    bucket.toLowerCase() !== bucket ||
    bucket.length < 3
  ) {
    endpointParams.ForcePathStyle = true;
  }

  if (endpointParams.DisableMultiRegionAccessPoints) {
    // inconsistent naming
    endpointParams.disableMultiRegionAccessPoints = true;
    endpointParams.DisableMRAP = true;
  }

  return endpointParams;
};

const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/;
const IP_ADDRESS_PATTERN = /(\d+\.){3}\d+/;
const DOTS_PATTERN = /\.\./;
/**
 * @internal
 */
export const DOT_PATTERN = /\./;
/**
 * @internal
 */
export const S3_HOSTNAME_PATTERN = /^(.+\.)?s3(-fips)?(\.dualstack)?[.-]([a-z0-9-]+)\./;

/**
 * Determines whether a given string is DNS compliant per the rules outlined by
 * S3. Length, capitaization, and leading dot restrictions are enforced by the
 * DOMAIN_PATTERN regular expression.
 * @internal
 *
 * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
 */
export const isDnsCompatibleBucketName = (bucketName: string): boolean =>
  DOMAIN_PATTERN.test(bucketName) && !IP_ADDRESS_PATTERN.test(bucketName) && !DOTS_PATTERN.test(bucketName);

/**
 * @internal
 */
export const isArnBucketName = (bucketName: string): boolean => {
  // region and account are unused between service and bucket.
  const [arn, partition, service, , , bucket] = bucketName.split(":");

  const isArn = arn === "arn" && bucketName.split(":").length >= 6;
  const isValidArn = Boolean(isArn && partition && service && bucket);

  if (isArn && !isValidArn) {
    throw new Error(`Invalid ARN: ${bucketName} was an invalid ARN.`);
  }

  return isValidArn;
};
